const { randomBytes } = require("crypto");
const { WebSocket } = require("ws");
import logger from "../utils/log";
// 添加crypto模块用于哈希生成
const crypto = require('crypto');

// 常量定义，与Python edge-tts一致
const TRUSTED_CLIENT_TOKEN = '6A5AA1D4EAFF4E9FB37E23D68491D6F4';
const SEC_MS_GEC_VERSION = '1-130.0.2849.68';
const WIN_EPOCH = 11644473600;
const S_TO_NS = 1e9;

const FORMAT_CONTENT_TYPE = new Map([
  ["raw-16khz-16bit-mono-pcm", "audio/basic"],
  ["raw-48khz-16bit-mono-pcm", "audio/basic"],
  ["raw-8khz-8bit-mono-mulaw", "audio/basic"],
  ["raw-8khz-8bit-mono-alaw", "audio/basic"],

  ["raw-16khz-16bit-mono-truesilk", "audio/SILK"],
  ["raw-24khz-16bit-mono-truesilk", "audio/SILK"],

  ["riff-16khz-16bit-mono-pcm", "audio/x-wav"],
  ["riff-24khz-16bit-mono-pcm", "audio/x-wav"],
  ["riff-48khz-16bit-mono-pcm", "audio/x-wav"],
  ["riff-8khz-8bit-mono-mulaw", "audio/x-wav"],
  ["riff-8khz-8bit-mono-alaw", "audio/x-wav"],

  ["audio-16khz-32kbitrate-mono-mp3", "audio/mpeg"],
  ["audio-16khz-64kbitrate-mono-mp3", "audio/mpeg"],
  ["audio-16khz-128kbitrate-mono-mp3", "audio/mpeg"],
  ["audio-24khz-48kbitrate-mono-mp3", "audio/mpeg"],
  ["audio-24khz-96kbitrate-mono-mp3", "audio/mpeg"],
  ["audio-24khz-160kbitrate-mono-mp3", "audio/mpeg"],
  ["audio-48khz-96kbitrate-mono-mp3", "audio/mpeg"],
  ["audio-48khz-192kbitrate-mono-mp3", "audio/mpeg"],

  ["webm-16khz-16bit-mono-opus", "audio/webm; codec=opus"],
  ["webm-24khz-16bit-mono-opus", "audio/webm; codec=opus"],

  ["ogg-16khz-16bit-mono-opus", "audio/ogg; codecs=opus; rate=16000"],
  ["ogg-24khz-16bit-mono-opus", "audio/ogg; codecs=opus; rate=24000"],
  ["ogg-48khz-16bit-mono-opus", "audio/ogg; codecs=opus; rate=48000"],
]);

// DRM类用于生成Sec-MS-GEC令牌
class DRM {
  static clockSkewSeconds = 0.0;

  // 获取当前Unix时间戳（包含时钟校准）
  static getUnixTimestamp(): number {
    return Date.now() / 1000 + this.clockSkewSeconds;
  }

  // 生成Sec-MS-GEC令牌
  static generateSecMsGec(): string {
    // 获取当前时间戳（带时钟偏移校准）
    let ticks = this.getUnixTimestamp();

    // 切换到Windows文件时间纪元（1601-01-01 00:00:00 UTC）
    ticks += WIN_EPOCH;

    // 向下舍入到最接近的5分钟（300秒）
    ticks -= ticks % 300;

    // 转换ticks为100纳秒间隔（Windows文件时间格式）
    ticks *= S_TO_NS / 100;

    // 创建要哈希的字符串，通过连接ticks和trusted client token
    const strToHash = `${Math.floor(ticks)}${TRUSTED_CLIENT_TOKEN}`;

    // 计算SHA256哈希并返回大写的十六进制摘要
    return crypto.createHash('sha256').update(strToHash, 'ascii').digest('hex').toUpperCase();
  }
}

class Service {
  ws = null;

  executorMap;
  bufferMap;

  timer = null;

  constructor() {
    this.executorMap = new Map();
    this.bufferMap = new Map();
  }

  async connect() {
    const connectionId = randomBytes(16).toString("hex").toLowerCase();
    // 添加Sec-MS-GEC和Sec-MS-GEC-Version参数
    const secMsGec = DRM.generateSecMsGec();
    let url = `wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1?TrustedClientToken=${TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGec}&Sec-MS-GEC-Version=${SEC_MS_GEC_VERSION}&ConnectionId=${connectionId}`;
    
    logger.info(`正在连接Edge TTS服务: Sec-MS-GEC=${secMsGec}, Sec-MS-GEC-Version=${SEC_MS_GEC_VERSION}`);
    
    const wsOptions = {
      host: "speech.platform.bing.com",
      origin: "chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold",
      headers: {
        "User-Agent":
          "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.66 Safari/537.36 Edg/103.0.1264.44",
      },
    };
    
    logger.info(`WebSocket选项: ${JSON.stringify(wsOptions)}`);
    
    let ws = null;
    try {
      ws = new WebSocket(url, wsOptions);
    } catch (err) {
      logger.error(`创建WebSocket失败: ${err.message || String(err)}`);
      throw new Error(`创建WebSocket连接失败: ${err.message || String(err)}`);
    }
    
    return new Promise((resolve, reject) => {
      let connectTimeout = setTimeout(() => {
        if (ws && ws.readyState !== WebSocket.OPEN) {
          logger.error(`WebSocket连接超时`);
          ws.terminate();
          reject(new Error("WebSocket连接超时，请检查网络连接"));
        }
      }, 15000); // 15秒连接超时
      
      ws.on("open", () => {
        logger.info(`WebSocket连接成功建立`);
        clearTimeout(connectTimeout);
        resolve(ws);
      });
      
      ws.on("close", (code, reason) => {
        // 服务器会自动断开空闲超过30秒的连接
        clearTimeout(connectTimeout);
        this.ws = null;
        if (this.timer) {
          clearTimeout(this.timer);
          this.timer = null;
        }
        
        // 记录关闭原因和代码
        logger.info(`连接已关闭: ${reason} ${code}`);
        
        // 如果是不支持的声音错误，为每个未完成的请求提供更详细的错误信息
        const reasonStr = String(reason);
        if (reasonStr.includes("Unsupported voice")) {
          for (let [key, value] of this.executorMap) {
            value.reject(`连接已关闭: ${reason} ${code}`);
          }
        } else {
          for (let [key, value] of this.executorMap) {
            value.reject(`连接已关闭: ${reason} ${code}`);
          }
        }
        
        this.executorMap.clear();
        this.bufferMap.clear();
      });

      ws.on("message", (message, isBinary) => {
        let pattern = /X-RequestId:(?<id>[a-z|0-9]*)/;
        if (!isBinary) {
          let data = message.toString();
          if (data.includes("Path:turn.start")) {
            // 开始传输
            let matches = data.match(pattern);
            if (matches && matches.groups && matches.groups.id) {
              let requestId = matches.groups.id;
              this.bufferMap.set(requestId, Buffer.from([]));
            } else {
              logger.error(`无法从消息中提取requestId: ${data}`);
            }
          } else if (data.includes("Path:turn.end")) {
            // 结束传输
            let matches = data.match(pattern);
            if (matches && matches.groups && matches.groups.id) {
              let requestId = matches.groups.id;
              let executor = this.executorMap.get(requestId);
              if (executor) {
                this.executorMap.delete(requestId);
                let result = this.bufferMap.get(requestId);
                executor.resolve(result);
                logger.info(`传输完成：${requestId}……`);
              } else {
                logger.info(`请求已被丢弃：${requestId}`);
              }
            } else {
              logger.error(`无法从消息中提取requestId: ${data}`);
            }
          } else {
            // 记录其他文本消息以便调试
            logger.info(`收到WebSocket文本消息: ${data}`);
          }
        } else if (isBinary) {
          let separator = "Path:audio\r\n";
          let data = message;
          let contentIndex = data.indexOf(separator) + separator.length;
          
          if (contentIndex <= separator.length) {
            logger.error(`收到无效的二进制消息，找不到路径分隔符`);
            return;
          }

          let headers = data.slice(2, contentIndex).toString();
          let matches = headers.match(pattern);
          
          if (!matches || !matches.groups || !matches.groups.id) {
            logger.error(`无法从二进制消息头中提取requestId: ${headers}`);
            return;
          }
          
          let requestId = matches.groups.id;
          let content = data.slice(contentIndex);
          let buffer = this.bufferMap.get(requestId);
          
          if (buffer) {
            buffer = Buffer.concat([buffer, content], buffer.length+content.length);
            this.bufferMap.set(requestId, buffer);
          } else {
            logger.info(`请求已被丢弃：${requestId}`);
          }
        }
      });
      
      ws.on("error", (error) => {
        clearTimeout(connectTimeout);
        const errorMsg = `WebSocket连接失败: ${error.message || String(error)}`;
        logger.error(errorMsg);
        
        // 添加更多诊断信息
        logger.error(`WebSocket状态: ${ws.readyState}`);
        logger.error(`连接URL: ${url}`);
        
        if (error.code) {
          logger.error(`错误代码: ${error.code}`);
        }
        
        reject(new Error(errorMsg));
      });
    });
  }

  async convert(ssml, format) {
    if (this.ws == null || this.ws.readyState != WebSocket.OPEN) {
      logger.info("准备连接服务器……");
      let connection = await this.connect();
      this.ws = connection;
      logger.info("连接成功！");
    }
    const requestId = randomBytes(16).toString("hex").toLowerCase();
    let result = new Promise((resolve, reject) => {
      // 等待服务器返回后这个方法才会返回结果
      this.executorMap.set(requestId, {
        resolve,
        reject,
      });
      // 发送配置消息
      let configData = {
        context: {
          synthesis: {
            audio: {
              metadataoptions: {
                sentenceBoundaryEnabled: "false",
                wordBoundaryEnabled: "false",
              },
              outputFormat: format,
            },
          },
        },
      };
      let configMessage =
        `X-Timestamp:${Date()}\r\n` +
        "Content-Type:application/json; charset=utf-8\r\n" +
        "Path:speech.config\r\n\r\n" +
        JSON.stringify(configData);
      this.ws.send(configMessage, (configError) => {
        if (configError) {
          logger.error(`配置请求发送失败：${requestId}\n`);
        }

        // 发送SSML消息
        let ssmlMessage =
          `X-Timestamp:${Date()}\r\n` +
          `X-RequestId:${requestId}\r\n` +
          `Content-Type:application/ssml+xml\r\n` +
          `Path:ssml\r\n\r\n` +
          ssml;
        this.ws.send(ssmlMessage, (ssmlError) => {
          if (ssmlError) {
            logger.error(`SSML消息发送失败：${requestId}\n`);
          }
        });
      });
    });

    // 收到请求，清除超时定时器
    if (this.timer) {
      logger.info("收到新的请求，清除超时定时器");
      clearTimeout(this.timer);
    }
    // 设置定时器，超过10秒没有收到请求，主动断开连接
    this.timer = setTimeout(() => {
      if (this.ws && this.ws.readyState == WebSocket.OPEN) {
        this.ws.close(1000);
        this.timer = null;
      }
    }, 10000);

    let data = await Promise.race([
      result,
      new Promise((resolve, reject) => {
        // 如果超过 20 秒没有返回结果，则清除请求并返回超时
        setTimeout(() => {
          this.executorMap.delete(requestId);
          this.bufferMap.delete(requestId);
          reject("转换超时");
        }, 10000);
      }),
    ]);
    return data;
  }
}

const service = new Service();
const retry = async function (fn, times, errorFn, failedMessage) {
  let reason = {
    message: failedMessage ?? "多次尝试后失败",
    errors: [],
  };
  let lastError = null;
  
  for (let i = 0; i < times; i++) {
    try {
      return await fn();
    } catch (error) {
      if (errorFn) {
        errorFn(i, error);
      }
      
      // 保存最后一个错误以便检查它是否是特殊错误
      lastError = error;
      
      // 检查是否是不支持声音的错误，如果是，直接抛出而不是继续重试
      const errorStr = String(error);
      if (errorStr.includes("Unsupported voice") || 
          (errorStr.includes("连接已关闭") && errorStr.includes("voice"))) {
        throw error; // 直接抛出而不是继续重试
      }
      
      reason.errors.push(error);
    }
  }
  
  // 如果有错误，且最后一个错误包含具体信息，则使用该信息作为主要错误消息
  if (lastError) {
    const errorStr = String(lastError);
    if (errorStr.includes("Unsupported voice") || 
        errorStr.includes("连接已关闭") || 
        errorStr.includes("超时")) {
      reason.message = errorStr;
    }
  }
  
  throw reason;
};

const ra = async (text) => {
  try {
    // let format = "webm-24khz-16bit-mono-opus";
    let format = "audio-24khz-48kbitrate-mono-mp3";
    if (Array.isArray(format)) {
      throw new Error(`无效的音频格式：${format}`);
    }
    if (!FORMAT_CONTENT_TYPE.has(format)) {
      throw new Error(`无效的音频格式：${format}`);
    }

    let ssml = text;
    if (ssml == null) {
      throw new Error(`转换参数无效`);
    }
    
    // 先尝试从SSML中提取voice值
    const voiceMatch = ssml.match(/voice name="([^"]+)"/i);
    const voiceName = voiceMatch ? voiceMatch[1] : "未知声音";
    
    try {
      let result = await retry(
        async () => {
          let result = await service.convert(ssml, format);
          return result;
        },
        3,
        (index, error) => {
          logger.error(`第${index}次转换失败：${error}`);
        },
        "服务器多次尝试后转换失败"
      );
      return result;
    } catch (error) {
      // 检查是否是不支持的声音错误
      const errorString = String(error);
      
      // 更全面地检测不支持的声音错误
      if (errorString.includes("Unsupported voice") || 
          (errorString.includes("连接已关闭") && errorString.includes("voice"))) {
        // 特殊处理不支持的声音错误
        const errorMessage = `声音 "${voiceName}" 不受Edge TTS支持。建议尝试其他声音或切换到TTS88 API以获得更广泛的支持。`;
        logger.error(errorMessage);
        throw new Error(errorMessage);
      }
      
      // 如果是复杂错误对象，检查其中包含的错误信息
      if (error && typeof error === 'object' && error.errors && Array.isArray(error.errors)) {
        // 检查错误数组中是否有不支持声音的错误
        for (const subError of error.errors) {
          const subErrorStr = String(subError);
          if (subErrorStr.includes("Unsupported voice") || 
              (subErrorStr.includes("连接已关闭") && subErrorStr.includes("voice"))) {
            const errorMessage = `声音 "${voiceName}" 不受Edge TTS支持。建议尝试其他声音或切换到TTS88 API以获得更广泛的支持。`;
            logger.error(errorMessage);
            throw new Error(errorMessage);
          }
        }
      }
      
      // 其他错误继续抛出
      if (typeof error === 'string') {
        throw new Error(error);
      } else if (error instanceof Error) {
        throw error;
      } else if (error && typeof error === 'object' && error.message) {
        throw new Error(error.message);
      } else {
        throw new Error(String(error));
      }
    }
  } catch (error) {
    // 确保错误是一个Error对象
    const formattedError = error instanceof Error ? error : new Error(error.message || String(error));
    logger.error(`发生错误, ${formattedError.message}`);
    
    // 为了调试，记录详细的错误信息
    if (error.stack) {
      logger.error(`错误堆栈: ${error.stack}`);
    }
    
    throw formattedError;
  }
};

// ra(
//   `<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US">          <voice name="zh-CN-XiaoxiaoNeural"><prosody rate="0%" pitch="0%">如果喜欢这个项目的话请点个 Star 吧。</prosody ></voice > </speak >`
// );
export default ra;